using System;
using System.Runtime.InteropServices;

namespace NTrace
{
  public class MiniDump
  {
    private enum MiniDumpType
    {
      /// <summary>
      /// Include just the information necessary to capture stack traces for all existing threads in a process.
      /// </summary>
      MiniDumpNormal = 0x00000000,

      /// <summary>
      /// Include the data sections from all loaded modules. This results in the inclusion of global variables, which can make the minidump file significantly larger. For per-module control, use the ModuleWriteDataSeg enumeration value from MODULE_WRITE_FLAGS.
      /// </summary>
      MiniDumpWithDataSegs = 0x00000001,

      /// <summary>
      /// Include all accessible memory in the process. The raw memory data is included at the end, so that the initial structures can be mapped directly without the raw memory information. This option can result in a very large file.
      /// </summary>
      MiniDumpWithFullMemory = 0x00000002,

      /// <summary>
      /// Include high-level information about the operating system handles that are active when the minidump is made.
      /// </summary>
      MiniDumpWithHandleData = 0x00000004,

      /// <summary>
      /// Stack and backing store memory written to the minidump file should be filtered to remove all but the pointer values necessary to reconstruct a stack trace. Typically, this removes any private information.
      /// </summary>
      MiniDumpFilterMemory = 0x00000008,

      /// <summary>
      ///Stack and backing store memory should be scanned for pointer references to modules in the module list. If a module is referenced by stack or backing store memory, the ModuleWriteFlags member of the MINIDUMP_CALLBACK_OUTPUT structure is set to ModuleReferencedByMemory.
      /// </summary>
      MiniDumpScanMemory = 0x00000010,
    }

    [DllImport("Kernel32")]
    private static extern int GetCurrentThreadId();

    [DllImport("DbgHelp", SetLastError = true)]
    private static extern bool MiniDumpWriteDump(
      IntPtr processHandle,
      int processId,
      IntPtr fileHandle,
      MiniDumpType dumpType,
      IntPtr exceptionParam,
      IntPtr userStreamParam,
      IntPtr callbackParam);

    public static void WriteMiniDump(String path)
    {
      using (System.IO.FileStream dumpFile = new System.IO.FileStream(path, System.IO.FileMode.Create, System.IO.FileAccess.Write, System.IO.FileShare.None))
      {
        bool result = false;

        System.Diagnostics.Process currentProcess = System.Diagnostics.Process.GetCurrentProcess();
        result = MiniDumpWriteDump(
          currentProcess.Handle,
          currentProcess.Id,
          dumpFile.SafeFileHandle.DangerousGetHandle(),
          MiniDumpType.MiniDumpWithFullMemory, // Required for the ability to debug managed minidumps
          IntPtr.Zero,
          IntPtr.Zero,
          IntPtr.Zero);
        dumpFile.Flush();

        if (!result) throw new System.ComponentModel.Win32Exception();
      }
    }
  }
}